/**
 * 
 */
package org.gigi.security.repository.hibernate;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

import org.gigi.core.Page;
import org.gigi.security.domain.Group;
import org.gigi.security.domain.GroupUser;
import org.gigi.security.domain.GroupUserPk;
import org.gigi.security.domain.User;
import org.gigi.security.repository.GroupRepository;
import org.hibernate.Query;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.stereotype.Repository;

/**
 * 用户组持久层类。
 * 
 * @author Eugene Wang 2011-9-2
 * @see
 */
@Repository
public class HibernateGroupRepository extends AbstractHibernateRepository
		implements GroupRepository {

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.gigi.security.repository.RoleRepository#create(org.gigi.security.
	 * domain.Role)
	 */
	@Override
	public void create(Group group) {
		getSession().save(group);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.gigi.security.repository.RoleRepository#findById(long)
	 */
	@Override
	public Group findById(long id) {
		return (Group) getSession().get(Group.class, id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.gigi.security.repository.RoleRepository#delete(org.gigi.security.
	 * domain.Role)
	 */
	@Override
	public void delete(Group group) {
		group.setAuthorities(null);
		getSession().delete(group);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.gigi.security.repository.RoleRepository#update(org.gigi.security.
	 * domain.Role)
	 */
	@Override
	public void update(Group group) {
		getSession().update(group);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.gigi.security.repository.RoleRepository#findChildren(long)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<Group> findChildren(long parentId) {
		String hql = "from Group r WHERE r.parent.id = :parentId ORDER BY r.layerOrder ASC";
		if (Group.ROOT_ID == parentId) {
			hql = "from Group r WHERE r.parent.id IS NULL ORDER BY r.layerOrder ASC";
		}
		Query query = getSession().createQuery(hql);
		if (Group.ROOT_ID != parentId) {
			query.setParameter("parentId", parentId);
		}
		return query.list();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.gigi.security.repository.GroupRepository#getUserPage(long,
	 * org.gigi.core.Page)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Page<User> getUserPage(Group group, Page<User> page) {
		Long count = (Long) getSession()
				.createQuery(
						"select count(gu.id.username) from GroupUser gu WHERE gu.id.groupId=:groupId")
				.setLong("groupId", group.getId()).uniqueResult();
		Query query = getSession()
				.createQuery(
						"select gu.user from GroupUser gu WHERE gu.id.groupId=:groupId")
				.setLong("groupId", group.getId());
		query.setFirstResult(page.getStart());
		query.setMaxResults(page.getLimit());
		List<User> list = query.list();
		page.setData(list);
		page.setTotalCount(count);
		return page;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.gigi.security.repository.GroupRepository#addUsers(org.gigi.security
	 * .domain.Group, java.util.List)
	 */
	@Override
	public void addUsers(final List<GroupUser> groupUsers) {
		String sql = "INSERT INTO sec_rl_group_user(group_id, username) VALUES(?, ?)";
		batchUpdateGroupUsers(groupUsers, sql);
	}

	/**
	 * 批量增加或者删除用户组用户。
	 * @param groupUsers
	 * @param sql
	 */
	private void batchUpdateGroupUsers(final List<GroupUser> groupUsers,
			String sql) {
		getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {

			@Override
			public void setValues(PreparedStatement ps, int i)
					throws SQLException {
				GroupUser groupUser = groupUsers.get(i);
				GroupUserPk pk = groupUser.getId();
				ps.setLong(1, pk.getGroupId());
				ps.setString(2, pk.getUsername());
			}

			@Override
			public int getBatchSize() {
				return groupUsers.size();
			}
		});
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.gigi.security.repository.GroupRepository#removeUsers(org.gigi.security
	 * .domain.Group, java.util.List)
	 */
	@Override
	public void removeUsers(final List<GroupUser> groupUsers) {
		String sql = "DELETE FROM sec_rl_group_user WHERE group_id = ? and username = ?";
		batchUpdateGroupUsers(groupUsers, sql);
	}

	/* (non-Javadoc)
	 * @see org.gigi.security.repository.GroupRepository#getNonUserPage(org.gigi.security.domain.Group, org.gigi.core.Page)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Page<User> getNonUserPage(Group group, Page<User> page) {
		Long count = (Long) getSession()
				.createQuery(
						"select count(us.username) from User us where not exists (from GroupUser gu where gu.id.groupId=:groupId and gu.user = us)")
				.setLong("groupId", group.getId()).uniqueResult();
		Query query = getSession()
				.createQuery(
						"from User us where not exists (from GroupUser gu where gu.id.groupId=:groupId and gu.user = us)")
				.setLong("groupId", group.getId());
		query.setFirstResult(page.getStart());
		query.setMaxResults(page.getLimit());
		List<User> list = query.list();
		page.setData(list);
		page.setTotalCount(count);
		return page;
	}
}
